package com.maben.udp.server;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * 定义服务端
 **/
@Component
public class SocketServer implements ApplicationRunner {

    @Getter
    private Bootstrap bootstrap;

    /**
     * netty服务监听端口
     */
    @Value("${netty.port:8088}")
    private int port;
    /**
     * 主线程组数量
     */
    @Value("${netty.bossThread:1}")
    private int bossThread;

    /**
     * 启动netty服务器
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 创建两个线程组，bossGroup为接收请求的线程组，一般1-2个就行
        EventLoopGroup bossGroup = new NioEventLoopGroup(this.bossThread);
        //netty客户端引导启动器
        bootstrap = new Bootstrap();
        //把事件处理线程池添加进启动引导器
        bootstrap.group(bossGroup);
        //设置通道的建立方式,【NioDatagramChannel.class】采用数据包通道方式
        bootstrap.channel(NioDatagramChannel.class);
        //此处添加客户端的通道处理器
        bootstrap.handler(new SocketHandler());
        /*
         * 用来配置一些channel的参数，配置的参数会被ChannelConfig使用
         * BACKLOG用于构造服务端套接字ServerSocket对象，
         * 标识当服务器请求处理线程全满时，
         * 用于临时存放已完成三次握手的请求的队列的最大长度。
         * 如果未设置或所设置的值小于1，Java将使用默认值50
         */
        bootstrap.option(ChannelOption.SO_BACKLOG, 128);
        /*
         * 是否启用心跳保活机制。在双方TCP套接字建立连接后（即都进入ESTABLISHED状态）
         * 并且在两个小时左右上层没有任何数据传输的情况下，这套机制才会被激活。
         */
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        //客户端绑定端口并且开始发起连接请求
        ChannelFuture channelFuture = bootstrap.bind(this.port).sync();
        //查看一下操作是不是成功结束了
        if (channelFuture.isSuccess()) {
            //如果没有成功结束就处理一些事情,结束了就执行关闭服务端等操作
            System.out.println("server started:" + this.port);
        }
        //关闭服务端
        channelFuture.channel().closeFuture().sync();
        System.out.println("server is stopping!");
    }
}